﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Metadata.W3cXsd2001;


namespace Logic.Packet
{
    /// <summary>
    /// Server sends the message of the day.
    /// </summary>
    public class SRV_MessageOfTheDay : T4CBasePak
    {
        public SRV_MessageOfTheDay(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public string Message
        { get; set; }


        public override void ResolveData()
        {
            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4).Take(DataPak.Length - 4).ToArray());
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Message of the day : {0}", Message);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class SRV_UpdateCoordinates : T4CBasePak
    {
        Int16 XCoord;
        Int16 YCoord;
        /// <summary>
        /// unit skin ID
        /// </summary>
        ushort SkinId;
        /// <summary>
        /// unit ID
        /// </summary>
        uint UnitId;
        /// <summary>
        /// radiance from 0 to 100
        /// </summary>
        sbyte LightPercentage;
        /// <summary>
        /// 0 = monster, 1 = NPC, 2 = player
        /// </summary>
        sbyte UnitType;
        /// <summary>
        ///  visual health from red (0) to green (100)
        /// </summary>
        sbyte HealthPercentage;

        public SRV_UpdateCoordinates(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("UnitID {0} with SkindID {1} has move to X {2} Y {3} with {4}%HP", UnitId, SkinId, XCoord, YCoord, HealthPercentage);
            sb.AppendLine();
            return sb.ToString();
        }

        public override void ResolveData()
        {

            
            //Int16 hgf = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);

            XCoord = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
            SkinId = BitConverter.ToUInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
            UnitId = BitConverter.ToUInt32(DataPak.Skip(8).Take(4).Reverse().ToArray(), 0);
            
            LightPercentage = DataPak.Skip(12).Take(1).Select(c => unchecked((sbyte)c)).Single();
            UnitType = DataPak.Skip(13).Take(1).Select(c => unchecked((sbyte)c)).Single();
            HealthPercentage = DataPak.Skip(14).Take(1).Select(c => unchecked((sbyte)c)).Single();
        }
    }




    //}

    /// <summary>
    /// server is making sure client is at the right location
    /// </summary>
    public class SRV_SynchronizePlayerCoordinates : T4CBasePak
    {
        public SRV_SynchronizePlayerCoordinates(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        Int16 XCoord;
        Int16 YCoord;
        Int16 World;

        public override string Display()
        {
            return string.Format("Client coordinates were updated at X : {0} Y : {1} World : {2}", XCoord, YCoord, World);
        }
        public override void ResolveData()
        {
            XCoord = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
            World = BitConverter.ToInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
        }
    }

    public class SRV_KeepAlive : T4CBasePak
    {
        public SRV_KeepAlive(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Ping ?");
            sb.AppendLine();

            return sb.ToString();
        }
    }

    //public class SRV_PutPlayerInGame : T4CBasePak
    //{
    //}

    //public class SRV_PersonalSkills : T4CBasePak
    //{
    //}

    //public class SRV_GroupLeave : T4CBasePak
    //{
    //}

    //public class SRV_DeleteGroup : T4CBasePak
    //{
    //}

    public class SRV_AttackMissed : T4CBasePak
    {
        uint UnitID;
        uint TargetUnitID;// BUG: always 0
        byte LightPercentage;
        byte UnitType;// 0 = monster, 1 = NPC, 2 = player
        byte HealthPercentage;
        Int16 XCoord;
        Int16 YCoord;
        Int16 TargetX;
        Int16 TargetY;

        public SRV_AttackMissed(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override void ResolveData()
        {
            UnitID = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            TargetUnitID = BitConverter.ToUInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
            LightPercentage = DataPak.Skip(10).Take(1).Select(c => unchecked((byte)c)).Single();
            UnitType = DataPak.Skip(11).Take(1).Select(c => unchecked((byte)c)).Single();
            HealthPercentage = DataPak.Skip(12).Take(1).Select(c => unchecked((byte)c)).Single();
            XCoord = BitConverter.ToInt16(DataPak.Skip(13).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(15).Take(2).Reverse().ToArray(), 0);
            TargetX = BitConverter.ToInt16(DataPak.Skip(17).Take(2).Reverse().ToArray(), 0);
            TargetY = BitConverter.ToInt16(DataPak.Skip(19).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("UnitID {0} missed his attack on target {1} at X {2} Y {3} with {4}%HP", UnitID, TargetUnitID, TargetX, TargetY, HealthPercentage);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_PopupUnit : T4CBasePak
    {
        Int16 XCoord;
        Int16 YCoord;
        ushort SkinID;
        uint UnitID;
        byte LightPercentage;
        byte UnitType; // 0 = monster, 1 = NPC, 2 = player
        byte HealthPercentage;

        public SRV_PopupUnit(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            XCoord = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
            SkinID = BitConverter.ToUInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
            UnitID = BitConverter.ToUInt32(DataPak.Skip(8).Take(4).Reverse().ToArray(), 0);
            LightPercentage = DataPak.Skip(12).Take(1).Select(c => unchecked((byte)c)).Single();
            UnitType = DataPak.Skip(13).Take(1).Select(c => unchecked((byte)c)).Single();
            HealthPercentage = DataPak.Skip(14).Take(1).Select(c => unchecked((byte)c)).Single();
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("UnitID {0} with SkinID {1} has respawned at X {2} Y {3} with {4}%HP", UnitID, SkinID, XCoord, YCoord, HealthPercentage);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_Login : T4CBasePak
    {
        byte Status;
        string Message;
        public SRV_Login(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            Status = DataPak.Skip(2).Take(1).Select(c => unchecked((byte)c)).Single();
            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(3).Take(DataPak.Length - 3).ToArray());
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Server sent status {0} with message : {1}", Status, Message);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    //public class SRV_DeletePlayer : T4CBasePak
    //{
    //}

    //public class SRV_RemoveUnit : T4CBasePak
    //{
    //}

    //public class SRV_SetUnitAppearance : T4CBasePak
    //{
    //}

    public class SRV_SendPeriphericObjects : T4CBasePak
    {
        /// <summary>
        /// number of units
        /// </summary>
        public ushort UnitCount { get; set; }
        public List<PeriphericObject> PeriphericObjects { get; set; }

        public SRV_SendPeriphericObjects(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            UnitCount = BitConverter.ToUInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            PeriphericObjects = new List<PeriphericObject>();
            for (int i = 0; i < UnitCount; i++)
            {
                PeriphericObject periphObject = new PeriphericObject();
                periphObject.XCoord = BitConverter.ToUInt16(DataPak.Skip(2 + 2 + i * 13).Take(2).Reverse().ToArray(), 0);
                periphObject.YCoord = BitConverter.ToUInt16(DataPak.Skip(2 + 2 + i * 13 + 2).Take(2).Reverse().ToArray(), 0);
                periphObject.SkinID = BitConverter.ToUInt16(DataPak.Skip(2 + 2 + i * 13 + 4).Take(2).Reverse().ToArray(), 0);
                periphObject.UnitID = BitConverter.ToUInt32(DataPak.Skip(2 + 2 + i * 13 + 6).Take(4).Reverse().ToArray(), 0);
                periphObject.LightPercentage = DataPak.Skip(2 + 2 + i * 13 + 10).Take(1).Select(c => unchecked((byte)c)).Single();
                periphObject.UnitType = DataPak.Skip(2 + 2 + i * 13 + 11).Take(1).Select(c => unchecked((byte)c)).Single();
                periphObject.HealthPercentage = DataPak.Skip(2 + 2 + i * 13 + 12).Take(1).Select(c => unchecked((byte)c)).Single();
                PeriphericObjects.Add(periphObject);
            }
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("There is {0} to display around you.", UnitCount);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_BackpackItems : T4CBasePak
    {
        public byte Unknown { get; set; }
        public int PlayerID { get; set; }
        public ushort ItemCount { get; set; }
        public List<BackPackItem> BackPackItems { get; set; }
        public SRV_BackpackItems(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override void ResolveData()
        {
            Unknown = DataPak.Skip(2).Take(1).Select(c => unchecked((byte)c)).Single();
            PlayerID = BitConverter.ToInt32(DataPak.Skip(3).Take(4).Reverse().ToArray(), 0);
            ItemCount = BitConverter.ToUInt16(DataPak.Skip(7).Take(2).Reverse().ToArray(), 0);
            BackPackItems = new List<BackPackItem>();
            for (int i = 0; i < ItemCount; i++)
            {

                BackPackItem item = new BackPackItem();
                item.SkinID = BitConverter.ToUInt16(DataPak.Skip(9 + i * 16).Take(2).Reverse().ToArray(), 0);
                item.UnitID = BitConverter.ToUInt32(DataPak.Skip(9 + i * 16 + 2).Take(4).Reverse().ToArray(), 0);
                item.ObjectID = BitConverter.ToUInt16(DataPak.Skip(9 + i * 16 + 6).Take(2).Reverse().ToArray(), 0);
                item.Quantity = BitConverter.ToUInt32(DataPak.Skip(9 + i * 16 + 8).Take(4).Reverse().ToArray(), 0);
                item.Unknown = BitConverter.ToUInt32(DataPak.Skip(9 + i * 16 + 12).Take(4).Reverse().ToArray(), 0);
                BackPackItems.Add(item);
            }
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Your player ID {0} has {1} items in its inventory.", PlayerID, ItemCount);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    //public class SRV_EquippedItems : T4CBasePak
    //{
    //}

    public class SRV_ServerShutdown : T4CBasePak
    {
        public SRV_ServerShutdown(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            base.ResolveData();
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Server is shutting down...");
            sb.AppendLine();

            return sb.ToString();
        }
    }

    //public class SRV_PersonalPCList : T4CBasePak
    //{
    //}

    public class SRV_IndirectTalk : T4CBasePak
    {
        /// <summary>
        /// Player ID in database
        /// </summary>
        public uint SenderId { get; set; }

        /// <summary>
        /// Current orientation (no change == 0)
        /// </summary>
        public byte SenderOrientation { get; set; }

        /// <summary>
        /// Unused? usually 00 00 BE BE
        /// </summary>
        public uint TextColor { get; set; }

        /// <summary>
        /// 0 = player, 1 = NPC
        /// </summary>
        public byte SenderType { get; set; }

        /// <summary>
        /// Message to display
        /// </summary>
        public string Message { get; set; }

        public string PlayerName { get; set; }

        public SRV_IndirectTalk(T4CBasePak pak) : base(pak.Data) { }

        public override void ResolveData()
        {

            SenderId = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            SenderOrientation = DataPak.Skip(6).Take(1).Single();
            TextColor = BitConverter.ToUInt32(DataPak.Skip(7).Take(4).Reverse().ToArray(), 0);
            SenderType = DataPak.Skip(11).Take(1).Single();

            //reverse numeric values
            Int16 messageLength = BitConverter.ToInt16(DataPak.Skip(12).Take(2).Reverse().ToArray(), 0);
            Int16 playerNameLength = BitConverter.ToInt16(DataPak.Skip(14 + messageLength).Take(2).Reverse().ToArray(), 0);

            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(14).Take(messageLength).ToArray());
            PlayerName = ASCIIEncoding.ASCII.GetString(DataPak.Skip(14 + messageLength + 2).Take(playerNameLength).ToArray());
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Player {0} (Id:{1}) says {2}", PlayerName, SenderId, Message);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class SRV_Page : T4CBasePak
    {
        public string SenderPlayerName { get; set; }
        public string Message { get; set; }

        public SRV_Page(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            Int16 senderPlayerNameSize = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            SenderPlayerName = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4).Take(senderPlayerNameSize).ToArray());
            Int16 messageize = BitConverter.ToInt16(DataPak.Skip(4 + senderPlayerNameSize).Take(2).Reverse().ToArray(), 0);
            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(6 + senderPlayerNameSize).Take(messageize).ToArray());
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Player {0} pages you : {1} ", SenderPlayerName, Message);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    //public class SRV_Reroll : T4CBasePak
    //{
    //}

    public class SRV_UpdateLife : T4CBasePak
    {
        public int Health { get; set; }
        public int MaxHealth { get; set; }

        public SRV_UpdateLife(T4CBasePak pak) : base(pak.Data) { }

        public override void ResolveData()
        {
            //reverse numeric values
            Health = BitConverter.ToInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            MaxHealth = BitConverter.ToInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("HP : {0} / {1}", Health, MaxHealth);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    //public class SRV_BroadcastTextChange : T4CBasePak
    //{
    //}

    //public class SRV_UnitName : T4CBasePak
    //{
    //}

    //public class SRV_BreakConversation : T4CBasePak
    //{
    //}

    //public class SRV_UpdateLevel : T4CBasePak
    //{
    //}

    //public class SRV_ReturnToMenu : T4CBasePak
    //{
    //}

    //public class SRV_TrainList : T4CBasePak
    //{
    //}

    //public class SRV_BuyList : T4CBasePak
    //{
    //}

    public class SRV_PersonalStats : T4CBasePak
    {
        public int Health { get; set; }
        public int MaxHealth { get; set; }
        public Int16 Mana { get; set; }
        public Int16 MaxMana { get; set; }
        public Int64 XP { get; set; }
        public Int16 BoostedArmor { get; set; }
        public Int16 Armor { get; set; }
        public Int16 BoostedStrength { get; set; }
        public Int16 BoostedEndurance { get; set; }
        public Int16 BoostedDexterity { get; set; }
        public Int16 BoostedWillpower { get; set; } // unused
        public Int16 BoostedWisdom { get; set; }
        public Int16 BoostedIntelligence { get; set; }
        public Int16 BoostedLuck { get; set; } // unused
        public Int16 StatPoints { get; set; }
        public Int16 Strength { get; set; }
        public Int16 Endurance { get; set; }
        public Int16 Dexterity { get; set; }
        public Int16 Willpower { get; set; } // unused
        public Int16 Wisdom { get; set; }
        public Int16 Intelligence { get; set; }
        public Int16 Luck { get; set; } // unused
        public Int16 Level { get; set; }
        public Int16 SkillPoints { get; set; }
        public Int16 Luggage { get; set; }
        public Int16 MaxLuggage { get; set; }
        public Int16 Karma { get; set; }
        public Int16 BaseHealth { get; set; }

        public SRV_PersonalStats(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            Health = BitConverter.ToInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            MaxHealth = BitConverter.ToInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
            Mana = BitConverter.ToInt16(DataPak.Skip(10).Take(2).Reverse().ToArray(), 0);
            MaxMana = BitConverter.ToInt16(DataPak.Skip(12).Take(2).Reverse().ToArray(), 0);
            XP = BitConverter.ToInt64(DataPak.Skip(14).Take(8).Reverse().ToArray(), 0);
            BoostedArmor = BitConverter.ToInt16(DataPak.Skip(22).Take(2).Reverse().ToArray(), 0);
            Armor = BitConverter.ToInt16(DataPak.Skip(24).Take(2).Reverse().ToArray(), 0);
            BoostedStrength = BitConverter.ToInt16(DataPak.Skip(26).Take(2).Reverse().ToArray(), 0);
            BoostedEndurance = BitConverter.ToInt16(DataPak.Skip(28).Take(2).Reverse().ToArray(), 0);
            BoostedDexterity = BitConverter.ToInt16(DataPak.Skip(30).Take(2).Reverse().ToArray(), 0);
            BoostedWillpower = BitConverter.ToInt16(DataPak.Skip(32).Take(2).Reverse().ToArray(), 0);
            BoostedWisdom = BitConverter.ToInt16(DataPak.Skip(34).Take(2).Reverse().ToArray(), 0);
            BoostedIntelligence = BitConverter.ToInt16(DataPak.Skip(36).Take(2).Reverse().ToArray(), 0);
            BoostedLuck = BitConverter.ToInt16(DataPak.Skip(38).Take(2).Reverse().ToArray(), 0);
            StatPoints = BitConverter.ToInt16(DataPak.Skip(40).Take(2).Reverse().ToArray(), 0);
            Strength = BitConverter.ToInt16(DataPak.Skip(42).Take(2).Reverse().ToArray(), 0);
            Endurance = BitConverter.ToInt16(DataPak.Skip(44).Take(2).Reverse().ToArray(), 0);
            Dexterity = BitConverter.ToInt16(DataPak.Skip(46).Take(2).Reverse().ToArray(), 0);
            Willpower = BitConverter.ToInt16(DataPak.Skip(48).Take(2).Reverse().ToArray(), 0);
            Wisdom = BitConverter.ToInt16(DataPak.Skip(50).Take(2).Reverse().ToArray(), 0);
            Intelligence = BitConverter.ToInt16(DataPak.Skip(52).Take(2).Reverse().ToArray(), 0);
            Luck = BitConverter.ToInt16(DataPak.Skip(54).Take(2).Reverse().ToArray(), 0);
            Level = BitConverter.ToInt16(DataPak.Skip(56).Take(2).Reverse().ToArray(), 0);
            SkillPoints = BitConverter.ToInt16(DataPak.Skip(58).Take(2).Reverse().ToArray(), 0);
            Luggage = BitConverter.ToInt16(DataPak.Skip(60).Take(2).Reverse().ToArray(), 0);
            MaxLuggage = BitConverter.ToInt16(DataPak.Skip(62).Take(2).Reverse().ToArray(), 0);
            Karma = BitConverter.ToInt16(DataPak.Skip(64).Take(2).Reverse().ToArray(), 0);
            BaseHealth = BitConverter.ToInt16(DataPak.Skip(66).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Personal Stats :  {0} / {1} HP {2} / {3} MP with {4} XP {5} / {6} Luggage, Level : {7} ", Health, MaxHealth, Mana, MaxMana, XP, Luggage, MaxLuggage, Level);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    //public class SRV_UpdateXP : T4CBasePak
    //{
    //}

    //public class SRV_UpdateTime : T4CBasePak
    //{
    //}

    //public class SRV_FromPreInGameToInGame : T4CBasePak
    //{
    //}

    public class SRV_ChannelMessage : T4CBasePak
    {
        /// <summary>
        /// Channel
        /// </summary>
        public string ChannelName { get; set; }

        /// <summary>
        /// Player name
        /// </summary>
        public string PlayerName { get; set; }

        /// <summary>
        /// Message to display
        /// </summary>
        public string Message { get; set; }

        public SRV_ChannelMessage(T4CBasePak pak) : base(pak.Data) { }

        public override void ResolveData()
        {
            //reverse numeric values
            Int16 channelLength = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            Int16 playerLength = BitConverter.ToInt16(DataPak.Skip(4 + channelLength).Take(2).Reverse().ToArray(), 0);
            Int16 messageLength = BitConverter.ToInt16(DataPak.Skip(4 + channelLength + 2 + playerLength).Take(2).Reverse().ToArray(), 0);

            ChannelName = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4).Take(channelLength).ToArray());
            PlayerName = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4 + channelLength + 2).Take(playerLength).ToArray());
            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4 + channelLength + 2 + playerLength + 2).Take(messageLength).ToArray());
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Channel {0} : Player {1} says {2}", ChannelName, PlayerName, Message);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    //public class SRV_ChannelUsers : T4CBasePak
    //{
    //}

    //public class SRV_PlayerList : T4CBasePak
    //{
    //}

    //public class SRV_UpdateGold : T4CBasePak
    //{
    //}

    //public class SRV_TeachList : T4CBasePak
    //{
    //}

    //public class SRV_SellList : T4CBasePak
    //{
    //}

    public class SRV_ServerMessage : T4CBasePak
    {
        uint Unused; // was color, but client sets it to 0x00FF6400 (blue). Can be nulled.
        string Message;

        public SRV_ServerMessage(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            Unused = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            Int16 messageSize = BitConverter.ToInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(8).Take(messageSize).ToArray());
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("sends the following system message : {0}", Message);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class SRV_InfoMessage : T4CBasePak
    {
        uint Unknown1 { get; set; }
        uint Color { get; set; } // alpha blue green red format
        string Message { get; set; }
        public SRV_InfoMessage(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            Unknown1 = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            Color = BitConverter.ToUInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
            Int16 messageSize = BitConverter.ToInt16(DataPak.Skip(10).Take(2).Reverse().ToArray(), 0);
            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(12).Take(messageSize).ToArray());
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Sends this information message : {0} ", Message);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_AttackSuccess : T4CBasePak
    {
        uint UnitID;
        uint TargetUnitID; // BUG: always 0
        Int16 XCoord;
        Int16 YCoord;
        Int16 TargetX;
        Int16 TargetY;

        public SRV_AttackSuccess(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            UnitID = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            TargetUnitID = BitConverter.ToUInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
            XCoord = BitConverter.ToInt16(DataPak.Skip(10).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(12).Take(2).Reverse().ToArray(), 0);
            TargetX = BitConverter.ToInt16(DataPak.Skip(14).Take(2).Reverse().ToArray(), 0);
            TargetY = BitConverter.ToInt16(DataPak.Skip(16).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("UnitID {0} succeeded his attack on target {1} at X {2} Y {3} ", UnitID, TargetUnitID, TargetX, TargetY);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_SkillSuccess : T4CBasePak
    {
        Int16 SkillID { get; set; }
        Int16 Value { get; set; } // unused ?
        public SRV_SkillSuccess(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            SkillID = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            Value = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("You successfully used skill id {0} with value {1} ", SkillID, Value);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_TeleportPlayer : T4CBasePak
    {
        public Int16 XCoord { get; set; }
        public Int16 YCoord { get; set; }
        public Int16 World { get; set; }

        public SRV_TeleportPlayer(T4CBasePak pak)
            : base(pak.Data)
        {
        }

        public override void ResolveData()
        {
            XCoord = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
            World = BitConverter.ToInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is teleporting you to X : {0} Y : {1} World : {2}", XCoord, YCoord, World);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_ItemName : T4CBasePak
    {
        public uint ItemID { get; set; }
        public string ItemName { get; set; }

        public SRV_ItemName(T4CBasePak pak)
            : base(pak.Data)
        {

        }


        public override void ResolveData()
        {
            //Not sure...
            //Looks like item id is player id?
            ItemID = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            // Personal fix wiki is not up to date on this pak.
            Int16 itemNameLength = BitConverter.ToInt16(DataPak.Skip(7).Take(2).Reverse().ToArray(), 0);
            ItemName = ASCIIEncoding.ASCII.GetString(DataPak.Skip(9).Take(itemNameLength).ToArray());
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is replying Item id {0} = {1}  ", ItemID, ItemName);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    //public class SRV_NoUnitInView : T4CBasePak
    //{
    //}

    //public class SRV_PersonalSpellList : T4CBasePak
    //{
    //}

    public class SRV_CastingSpell : T4CBasePak
    {
        Int16 EffectID;
        uint SourceID;
        uint TargetID;
        Int16 TargetX;
        Int16 TargetY;
        Int16 SourceX;
        Int16 SourceY;
        uint CreatedUnitID;
        uint Unknown;

        public SRV_CastingSpell(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            EffectID = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            SourceID = BitConverter.ToUInt32(DataPak.Skip(4).Take(4).Reverse().ToArray(), 0);
            TargetID = BitConverter.ToUInt32(DataPak.Skip(8).Take(4).Reverse().ToArray(), 0);
            TargetX = BitConverter.ToInt16(DataPak.Skip(12).Take(2).Reverse().ToArray(), 0);
            TargetY = BitConverter.ToInt16(DataPak.Skip(14).Take(2).Reverse().ToArray(), 0);
            SourceX = BitConverter.ToInt16(DataPak.Skip(16).Take(2).Reverse().ToArray(), 0);
            SourceY = BitConverter.ToInt16(DataPak.Skip(18).Take(2).Reverse().ToArray(), 0);
            CreatedUnitID = BitConverter.ToUInt32(DataPak.Skip(20).Take(4).Reverse().ToArray(), 0);
            Unknown = BitConverter.ToUInt32(DataPak.Skip(24).Take(4).Reverse().ToArray(), 0);

        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("UnitID {0} at X {1} Y {2}  has targeted {3} at X {4} Y {5} with spell effect id {6} ", SourceID, SourceX, SourceY, TargetID, TargetX, TargetY, EffectID);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_ServerInformation : T4CBasePak
    {
        uint Version;
        Int16 PatchServerCount;

        public SRV_ServerInformation(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            Version = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            PatchServerCount = BitConverter.ToInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Version {0} with Patch Server Count : {1} ", Version, PatchServerCount);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_UpdateMana : T4CBasePak
    {
        public Int16 Mana { get; set; }

        public SRV_UpdateMana(T4CBasePak pak) : base(pak.Data) { }

        public override void ResolveData()
        {
            //reverse numeric values
            Mana = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Current Mana : {0}", Mana);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class SRV_UnitAppearance : T4CBasePak
    {
        public ushort SkinId { get; set; }
        public int UnitId { get; set; }

        /// <summary>
        /// radiance from 0 to 100
        /// </summary>
        public byte LightPercentage { get; set; }

        /// <summary>
        ///  0 = monster, 1 = NPC, 2 = player
        /// </summary>
        public byte UnitType { get; set; }

        /// <summary>
        /// visual health from red (0) to green (100)
        /// </summary>
        public byte HealthPercentage { get; set; }

        public SRV_UnitAppearance(T4CBasePak pak) : base(pak.Data) { }

        public override void ResolveData()
        {
            //reverse numeric values
            SkinId = BitConverter.ToUInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            UnitId = BitConverter.ToInt32(DataPak.Skip(4).Take(4).Reverse().ToArray(), 0);
            LightPercentage = DataPak.Skip(8).Take(1).Single();
            UnitType = DataPak.Skip(9).Take(1).Single();
            HealthPercentage = DataPak.Skip(10).Take(1).Single();
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("UnitId {0} / SkindId {1} / Light {2} % / UnitType {3} / Health {4} %",
                UnitId, SkinId, LightPercentage, UnitType, HealthPercentage);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    //public class SRV_UnitNotFound : T4CBasePak
    //{
    //}

    public class SRV_NoMoreItem : T4CBasePak
    {
        public Int16 ItemID { get; set; }
        public SRV_NoMoreItem(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            ItemID = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Item {0} is out of stock!", ItemID);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    //public class SRV_CreateGtroup : T4CBasePak
    //{
    //}

    //public class SRV_GroupInvite : T4CBasePak
    //{
    //}

    public class SRV_ActivateUserSpell : T4CBasePak
    {
        public int SpellID { get; set; }
        public int Duration1 { get; set; }
        public int Duration2 { get; set; }
        public int IconID { get; set; }
        public string Description { get; set; }

        public SRV_ActivateUserSpell(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            SpellID = BitConverter.ToInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            Duration1 = BitConverter.ToInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
            Duration2 = BitConverter.ToInt32(DataPak.Skip(10).Take(4).Reverse().ToArray(), 0);
            IconID = BitConverter.ToInt32(DataPak.Skip(14).Take(4).Reverse().ToArray(), 0);
            Int16 descriptionLength = BitConverter.ToInt16(DataPak.Skip(18).Take(2).Reverse().ToArray(), 0);
            Description = ASCIIEncoding.ASCII.GetString(DataPak.Skip(20).Take(descriptionLength).ToArray());
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Spell {0} with {1} and {2} is {3}", SpellID, Duration1, Duration2, Description);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class SRV_SpellOff : T4CBasePak
    {
        public int SpellID { get; set; }

        public SRV_SpellOff(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            SpellID = BitConverter.ToInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("removed spell id {0}", SpellID);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    //public class SRV_ToggleGroupAutoSplit : T4CBasePak
    //{
    //}

    //public class SRV_PlayerExists : T4CBasePak
    //{
    //}

    //public class SRV_PatchServerInformation : T4CBasePak
    //{
    //}

    //public class SRV_Rob : T4CBasePak
    //{
    //}

    //public class SRV_DispelRob : T4CBasePak
    //{
    //}

    public class SRV_ArrowMissed : T4CBasePak
    {
        public uint UnitID { get; set; }
        public Int16 XCoord { get; set; }
        public Int16 YCoord { get; set; }
        public byte HealthPercentage { get; set; }
        public SRV_ArrowMissed(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            UnitID = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            XCoord = BitConverter.ToInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(8).Take(2).Reverse().ToArray(), 0);
            HealthPercentage = DataPak.Skip(10).Take(1).Single();
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Arrow misses target {0} at X {1} Y {2} with {3}%HP", UnitID, XCoord, YCoord, HealthPercentage);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_ArrowSuccess : T4CBasePak
    {
        public uint UnitID { get; set; }
        public Int16 XCoord { get; set; }
        public Int16 YCoord { get; set; }
        public byte HealthPercentage { get; set; }
        public SRV_ArrowSuccess(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            UnitID = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            XCoord = BitConverter.ToInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(8).Take(2).Reverse().ToArray(), 0);
            HealthPercentage = DataPak.Skip(10).Take(1).Single();
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Arrow hits target {0} at X {1} Y {2} with {3}%HP", UnitID, XCoord, YCoord, HealthPercentage);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    //public class SRV_ServerFlags : T4CBasePak
    //{
    //}

    //public class SRV_SeraphArrival : T4CBasePak
    //{
    //}

    //public class SRV_AuthenticateVersion : T4CBasePak
    //{
    //}

    //public class SRV_ResetRegistryInventory : T4CBasePak
    //{
    //}

    public class SRV_MaxCharactersPerAccount : T4CBasePak
    {
        byte MaxCharacters { get; set; } // max amount of characters allowed per account (usually 3)
        public SRV_MaxCharactersPerAccount(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            MaxCharacters = DataPak.Skip(2).Take(1).Single();
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("On this server you can have a maximum of {0} characters per account.", MaxCharacters);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_ToggleWeather : T4CBasePak
    {
        Int16 Enabled { get; set; }  // set to 0x0001 to enable rain, 0x0000 to disable
        public SRV_ToggleWeather(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            Enabled = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Rain is {0} where 0x0001 = enable rain, 0x0000 = disable .", Enabled);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_OpenURL : T4CBasePak
    {
        string UrlToOpen; // goes straight into a ShellExecute, prefixed with "http://"
        public SRV_OpenURL(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            Int16 messageSize = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            UrlToOpen = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4).Take(messageSize).ToArray());
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Opening url {0}", UrlToOpen);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    //public class SRV_ChestItems : T4CBasePak
    //{
    //}

    public class SRV_OpenChest : T4CBasePak
    {
        public SRV_OpenChest(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            base.ResolveData();
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Opening the chest interface");
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class SRV_CloseChest : T4CBasePak
    {
        public SRV_CloseChest(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            base.ResolveData();
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Closing the chest interface");
            sb.AppendLine();
            return sb.ToString();
        }
    }

    //public class SRV_RequestExchange : T4CBasePak
    //{
    //}

    //public class SRV_ItemDescription : T4CBasePak
    //{

    //}
}
